home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: iutil.c,v 0.91 1994/02/20 00:53:07 zhao Pre-Release $
- *
- *. This file is part of BIT shareware package. After the two weeks of
- * free evaluation period, you are encouraged (required) to register
- * your copy for a small registration fee, which is $35 for personal use
- * and $50 for commercial, government and institutional use.
- *
- * Copyright(c) 1993, 1994 by T.C. Zhao.
- * All rights reserved.
- *
- * Permission to use, copy, and distribute this software in its entirety
- * for non-commercial purposes is hereby granted, provided that the
- * above shareware and copyright notices and this permission notice
- * appear in all copies and their documentation.
- *
- * This software may be modified for your own use, but modified versions
- * may not be distributed without prior consent of the author.
- *
- * This software is provided "as is" without expressed or implied
- * warranty of any kind.
- *
- *.
- *
- * utilities dealing with memory allocations and image manipulations
- */
- #if !defined(lint) && defined(F_ID)
- char *id_iutil = "$Id: iutil.c,v 0.91 1994/02/20 00:53:07 zhao Pre-Release $";
- #endif
-
- #include "bit.h"
- #include "extern.h"
- #include "dmalloc.h"
-
- /****************** Defines and limits *****************************/
-
- #define CONVERT_TYPE /* controls the rgb->gray lookup table */
-
- #include "lookup.h"
-
- /*****************************************************************
- * Gather all recognized format info which is output by function out
- * defined as void (*out)(char *)
- ******************************************************************/
- void
- enumerate_formats(void (*out) (const char *))
- {
- char lstr[100];
- const char *fmt;
- IMG_IO *ios = img_io + totalfmt, *io = img_io;
-
- if (!out)
- {
- M_warn("EnumerateFormats", "Bad output function");
- return;
- }
-
- /* write only +, read only - */
- while (io < ios)
- {
- fmt = (!io->load) ? "%s(%s)+" :
- (io->dump ? "%s(%s)" : "%s(%s)-");
- sprintf(lstr, fmt, io->info, io->key);
- out(lstr);
- io++;
- }
- }
-
- /***************************************************************
- * Gather all formats that are capable of writing
- **************************************************************/
- void
- init_w_formats(void)
- {
- if (!totalwrite)
- {
- register IMG_IO *ios = img_io + totalfmt, *io = img_io;
-
- while (io < ios)
- {
- if (io->dump)
- wio[totalwrite++] = io;
- io++;
- }
- }
- }
-
-
- /****************************************************************
- * Insert a pixel into a matrix. Pixel is represented by
- * a 4-element vector, the first 3 is RGB component and the
- * 4th is the colorindex if the image is in CI
- ****************************************************************/
- void
- pack_pixel(IPTR im, void *m, int py, int px, int pc[])
- {
- if (IS_CI(im))
- {
- ((ci_t **) m)[py][px] = pc[3];
- }
- else
- {
- ((rgba_t **) m)[py][px] = Pack(pc[0], pc[1], pc[2]);
- }
- }
-
- /*************************************************************
- * pick a pixel from a matrix
- **************************************************************/
- void
- pick_pixel(IPTR im, void *m, int py, int px, int pc[])
- {
- int ci;
-
- if (IS_CI(im))
- {
- pc[3] = ci = ((ci_t **) m)[py][px];
- pc[0] = im->cmap->ct[0][ci];
- pc[1] = im->cmap->ct[1][ci];
- pc[2] = im->cmap->ct[2][ci];
- }
- else
- {
- rgba_t p = ((rgba_t **) m)[py][px];
- Unpack(p, pc[0], pc[1], pc[2]);
- pc[3] = 0;
- }
- }
-
- /****************************************************
- * Routines that deal with separate RGB matrices
- ***************************************************/
- void
- img_free_rgbmem(IPTR im)
- {
- free_mat(im->pc[0]);
- if (im->pc[0] != im->pc[1])
- { /* if equal, must be gray */
- free_mat(im->pc[1]);
- free_mat(im->pc[2]);
- }
- im->pc[0] = im->pc[1] = im->pc[2] = 0;
- }
-
- void
- img_replace_rgb(IPTR im, pc_t **r, pc_t **g, pc_t **b)
- {
- if (im->pc[0] != r)
- img_free_rgbmem(im);
- im->pc[0] = r;
- im->pc[1] = g;
- im->pc[2] = b;
- }
-
- /****************************************************************
- * get_rgbmem must get RM, GM, BM regardless of the image type.
- * otherwise, need to change many routines regarding R,G,B matrices
- ***************************************************************/
-
- int
- img_get_rgbmem(IPTR im)
- {
- pc_t **r, **g = 0, **b = 0;
-
- if (!(r = get_mat(im->h, im->w, sizeof(pc_t))) ||
- ! (g = get_mat(im->h, im->w, sizeof(pc_t))) ||
- ! (b = get_mat(im->h, im->w, sizeof(pc_t))))
- {
- free_mat(r);
- free_mat(g);
- free_mat(b);
- return -1;
- }
- img_replace_rgb(im, r, g, b);
- return 0;
- }
-
- /*********************************************************
- * routines that deal with raster mem
- *********************************************************/
- void
- img_free_rastermem(IPTR im)
- {
- if (im->size > 2 && im->mraster)
- {
- if (((char **) im->mraster)[0] != (char *) im->raster)
- {
- Bark("FreeRasterMem", "memory corrupt");
- return;
- }
- free_mat(im->mraster);
- im->size = im->ok = 0;
- im->mraster = 0;
- }
- return;
- }
-
- extern void exit(int);
-
- IPTR
- get_mem_imgptr(void)
- {
- const char *fn = "GetMemIptr";
- IPTR p = calloc(1, sizeof(*p));
-
- if (!p)
- {
- M_err(fn, mfailed);
- if (win_id > 0)
- Bark(fn, mfailed);
- clean_up();
- }
-
- /* initialize all pointers and non-zero default */
- p->type = T_FLEX;
- p->mraster = p->raster = 0;
- p->cmap = 0;
- p->pc[0] = p->pc[1] = p->pc[2] = 0;
- p->fp = 0;
- p->aspect = 1000;
- p->comm = 0;
-
- return p;
- }
-
- /*******************************************************
- * Colormaps
- *******************************************************/
-
- /* Demand a colormap. If unsuccesful, quit */
- CMPTR
- get_mem_cmap(void)
- {
- CMPTR p = calloc(1, sizeof(*p));
-
- if (!p)
- {
- M_err("GetMemCmap", mfailed);
- if (win_id > 0)
- Bark("GetMemCmap", mfailed);
- clean_up();
- }
- p->colors = p->ucolors = p->packed = 0;
-
- return p;
- }
-
- void
- free_mem_imgptr(IPTR p)
- {
- if (p)
- {
- p->ok = p->size = 0;
- p->mraster = 0;
- free(p);
- }
- }
-
- void
- free_mem_cmap(CMPTR p)
- {
- free(p);
- }
-
- int
- img_get_rastermem(IPTR im)
- {
- register void *p, **pp;
- register size_t esize = 0;
- const char *fn = "GetRasterMem";
-
- /* this theoretically should never happen */
- if (!im)
- {
- Bark(fn, "Something is very wrong");
- return -1;
- }
-
- if (im->type == T_FLEX || im->w < 1 || im->h < 1)
- {
- Bark(fn, "%s: Bad %s description", im->ifile,
- im->io ? im->io->key : "???");
- return -1;
- }
-
- if (IS_CI(im))
- im->esize = esize = sizeof(ci_t);
- else if (IS_CPACK(im))
- im->esize = esize = sizeof(rgba_t);
- else
- {
- Bark(fn, "Bad Image type");
- clean_up();
- }
-
- img_free_rastermem(im);
-
- if (!(p = get_mat(im->h, im->w, esize)))
- {
- im->size = 0;
- return -1;
- }
-
- pp = p;
- im->mraster = pp;
- im->raster = pp[0];
- im->size = esize * im->w * im->h;
-
- return 0;
- }
-
- /*
- * this function is really overkill, im->ok should be able to indicate if the
- * image is ready. Be on the safe side, also might catch unexpected errors
- */
- int
- image_ready(IPTR im, const char *func)
- {
- int p = (im != 0 && im->ok
- && im->size > 1
- && im->w >= 1
- && im->mraster
- && im->raster
- && (IS_CPACK(im) || IS_CI(im)));
-
- if (!p)
- Bark(func, "No image or bad type");
- return p;
- }
-
- /*
- * duplicate an image raster;
- */
- int
- img_dup_raster(IPTR new, IPTR old)
- {
- const char *fn = "RasterDup";
-
- if (!image_ready(old, fn) || !new)
- return -1;
-
- new->w = old->w;
- new->h = old->h;
- new->type = old->type;
-
- return (img_get_rastermem(new) < 0 ||
- memcpy(new->raster, old->raster, new->size) == 0) ? -1 : 0;
- }
-
- void
- img_free_cmap(IPTR im)
- {
- if (im && im->cmap)
- {
- free_mem_cmap(im->cmap);
- im->cmap = 0;
- }
- }
-
- /*****************************************************************
- * duplicate a colormap (free the old one if present)
- *****************************************************************/
-
- int
- img_dup_cmap(IPTR new, IPTR old)
- {
- if (!image_ready(old, "dup_raster") || !new)
- return -1;
- img_free_cmap(new);
- new->cmap = get_mem_cmap();
- return memcpy(new->cmap, old->cmap, sizeof(*old->cmap)) ? 0 : -1;
- }
-
- /*******************************************************************
- * duplicate an image and return the new image pointer
- ********************************************************************/
-
- IPTR
- img_dup(IPTR old)
- {
- IPTR new;
- int ok = -1;
-
- show_busy("ImageDup ...");
-
- new = get_mem_imgptr();
- if (memcpy(new, old, sizeof(*old)) != 0)
- {
- new->size = new->ok = 0;
- new->mraster = new->raster = 0;
- new->cmap = 0;
- ok = !(img_dup_cmap(new, old) || img_dup_raster(new, old));
- new->ok = ok;
- }
- end_busy();
-
- return ok ? new : 0;
- }
-
- void
- free_image_mem(IPTR im)
- {
- if (!im)
- return;
- img_free_cmap(im);
- img_free_rastermem(im);
- img_free_rgbmem(im);
- }
-
- /********************************************************************
- * free everything that is associated with the image structure img
- *
- * free_rastermem
- * free_cmap
- * free_imgptr
- *********************************************************************/
-
- void
- free_image(IPTR im)
- {
- if (im)
- {
- free_image_mem(im);
- free_mem_imgptr(im);
- }
- }
-
- /***********************************************************************
- * get the border offset into the image. Note MAXC is the maximum no. of
- * colors on one line(horizontal or vertical) can have to be considered
- * to be a border line. Coordinates are from Left to Right and Bottom to Top.
- *********************************************************************/
-
- #define MAXC 4
-
- #define DOIT(type,nouse) \
- register type **mras= im->mraster, *ras, first; \
- do { \
- ok= 1; ras= mras[h - 1]; \
- for (j= h - 1; j >= 0 && ok; j--,(*t)++,ras= mras[j]){ \
- first= *ras++; \
- for (i= 1 ; i < w && first== *ras;i++, ras++) \
- ; \
- ok= i== w; \
- } \
- h -= *t; ok= 1; ras= mras[0]; \
- for (j= 0; j < h && ok; j++, (*b)++, ras= mras[j]) { \
- for (i= 0, first= *ras; ++i < w && first== *ras++;) \
- ; \
- ok= i== w; \
- } \
- ok= 1; \
- for (*l= 0; *l < w && ok; (*l)++) { \
- first= mras[*b][*l]; \
- for (j= *b; j < h && ok; j++) \
- ok= first== mras[j][*l]; \
- } \
- ok= 1; \
- for (i= w - 1; i > *l && ok; i--, (*r)++) { \
- first= mras[*b][i]; \
- for (j= *b; j < h && ok; j++) \
- ok= first== mras[j][i]; \
- } \
- } while (ZERO)
-
- int
- img_get_border(IPTR im, int *b, int *l, int *t, int *r, int n)
- {
- register int i, j, ok, h, w;
-
- if (!image_ready(im, "Border"))
- return -1;
-
- *t = *l = *r = *b = 0;
- h = im->h;
- w = im->w;
-
- show_busy("PleaseWait ...");
-
- if (IS_CPACK(im))
- { /* in RGBA format */
- DOIT(rgba_t, n);
- }
- else
- {
- DOIT(ci_t, n);
- }
- end_busy();
-
- return 0;
- }
-
- /****************************************************************
- * Note not true histograms, rather histogram for RGB separately.
- * Histogram is not normalized.
- ****************************************************************/
- int
- img_get_histogram(IPTR im)
- {
- Hist_t *hist = im->cmap->p_h.hist;
- long total = im->w * im->h;
- int i, j;
- double ave[4];
-
- #ifdef MTRACE
- M_trace("Histogram", "Entering");
- #endif
-
- show_busy("GettingHist ...");
- (void) memset(hist, 0, sizeof(Hist_t) * 4);
-
- im->cmap->packed = 0; /* overwrite packed arrays */
-
- if (IS_CPACK(im))
- {
- register rgba_t *rgba = im->raster, *rs;
- register pc_t r;
- if (IS_GRAY(im))
- {
- for (rs = rgba + total; rgba < rs; rgba++)
- {
- r = (*rgba & PCMAXV);
-
- /* check overflows */
- if (++(hist[3][r]) == 0)
- (hist[3][r])--;
- }
- }
- else
- {
- register pc_t g, b;
- for (rs = rgba + total; rgba < rs; rgba++)
- {
- Unpack(*rgba, r, g, b);
- if (++(hist[0][r]) == 0)
- (hist[0][r])--;
- if (++(hist[1][g]) == 0)
- (hist[1][g])--;
- if (++(hist[2][b]) == 0)
- (hist[2][b])--;
- ++(hist[3][RGB2GRAY(r, g, b)]);
- }
- }
- }
- else
- { /* in cmap */
- register ci_t *ci = im->raster, *cis;
- register CMPTR m = im->cmap;
- register pc_t *r = m->ct[0], *g = m->ct[1], *b = m->ct[2];
- if (IS_GRAY(im))
- {
- for (cis = ci + total; ci < cis; ci++)
- {
- ++(hist[3][r[*ci]]);
- }
- }
- else
- {
- for (cis = ci + total; ci < cis; ci++)
- {
- ++(hist[0][r[*ci]]);
- ++(hist[1][g[*ci]]);
- ++(hist[2][b[*ci]]);
- ++(hist[3][RGB2GRAY(r[*ci], g[*ci], b[*ci])]);
- }
- }
- }
-
- if (IS_GRAY(im))
- {
- if (memcpy(hist[0], hist[3], sizeof(Hist_t)) == 0 ||
- memcpy(hist[1], hist[3], sizeof(Hist_t)) == 0 ||
- memcpy(hist[2], hist[3], sizeof(Hist_t)) == 0)
- {
- Bark("Histogram", "memcpy failed");
- return -1;
- }
- }
- /* get peak value and average */
- for (j = 0; j < 4; j++)
- {
- ave[j] = 0.0;
- hist[j][PCMAX] = 0.0;
- for (i = 0; i < PCMAX; i++)
- {
- if (hist[j][i] > hist[j][PCMAX])
- {
- hist[j][PCMAX] = hist[j][i];
- hist[j][PCMAX + 2] = i;
- }
- ave[j] += hist[j][i] * i;
- }
- hist[j][PCMAX + 1] = (ave[j] / total);
- }
- end_busy();
- #ifdef MTRACE
- M_trace("Histogram", "Exit");
- #endif
- return 0;
- }
-
-
- /******************************************************************
- * modify raster according the input function: f(x) Basically a
- * one-to-one mapping.
- *******************************************************************/
-
- void
- modify_rgb(register rgba_t *ras, long n, register pc_t *r,
- register pc_t *g, register pc_t *b)
- {
- register int rr, gg, bb;
- register rgba_t *rs;
-
- if (r == g)
- { /* must be grayscale images */
- for (rs = ras + n; ras < rs; ras++)
- {
- rr = *ras & PCMAXV;
- rr = *(r + rr);
- *ras = Pack(rr, rr, rr);
- }
- }
- else
- {
- for (rs = ras + n; ras < rs; ras++)
- {
- Unpack(*ras, rr, gg, bb);
- rr = r[rr];
- gg = g[gg];
- bb = b[bb];
- *ras = Pack(rr, gg, bb);
- }
- }
- }
-
- void
- modify_cpack_pixel(register rgba_t *ras, long total,
- register rgba_t old, register rgba_t new,
- register int sw)
- {
- register rgba_t *ra;
- for (ra = ras + total; ras < ra; ras++)
- {
- if (*ras == old)
- *ras = new;
- else if (sw && (*ras == new))
- *ras = old;
- }
- }
-
- /*******************************************************************
- * Modifies all rasters according to mapping given by nlut
- *********************************************************************/
- void
- modify_all_ci(register ci_t *ras, long total, register ci_t *nlut)
- {
- register ci_t *ra = ras + total;
-
- for (; ras < ra; ras++)
- *ras = nlut[*ras];
- }
-
- /***********************************************************************
- * this can be written as special case of modify_all_ci with 2 entris
- * that are not null transformations lut[i] == i.
- * But for simple swap, this is faster.
- ********************************************************************/
- void
- modify_ci_pixel(register ci_t *ras, long total,
- register ci_t old, register ci_t new, register int sw)
- {
- register ci_t *ra = ras + total;
- for (; ras < ra; ras++)
- {
- if (*ras == old)
- *ras = new;
- else if (sw && *ras == new)
- *ras = old;
- }
- }
-
- /* **************************************************************
- * replace all pixels that have oldp with newp. If sw is true
- * switch old and new
- ******************************************************************/
- void
- img_modify_pixel(IPTR im, int oldp[], int newp[], int sw)
- {
-
- show_busy("");
-
- if (IS_CPACK(im))
- {
- modify_cpack_pixel(im->raster, im->w * im->h,
- Pack(oldp[0], oldp[1], oldp[2]),
- Pack(newp[0], newp[1], newp[2]), sw);
- }
- else
- {
- modify_ci_pixel(im->raster, im->w * im->h,
- oldp[3], newp[3], sw);
- }
- end_busy();
- }
-
- /***************************************************************
- * Colormap routines
- ***************************************************************/
-
- void
- set_colmap(int n, pc_t *r, pc_t *g, pc_t *b)
- {
- register int i;
-
- for (i = 0; i < n; i++, r++, g++, b++)
- mapcolor(i, *r, *g, *b);
- }
-
- void
- set_cmap(CMPTR m)
- {
- set_colmap(m->colors, m->ct[0], m->ct[1], m->ct[2]);
- }
-
- void
- get_colmap(int n, pc_t *r, pc_t *g, pc_t *b)
- {
- register int i;
- short x, y, z;
-
- for (i = 0; i < n; i++, *r++ = x, *g++ = y, *b++ = z)
- getmcolor(i, &x, &y, &z);
- }
-
- void
- set_cmap_entry(CMPTR m, int fc[], int ci)
- {
- int i;
-
- if (ci >= MAXCML)
- {
- M_warn("SetCmapEntry", "Bad input");
- return;
- }
- for (i = 0; i < 3; i++)
- m->ct[i][ci] = fc[i];
- m->packed = 0;
- }
-
- void
- get_cmap_entry(CMPTR m, int fc[], int ci)
- {
- int i;
-
- if (ci >= MAXCML)
- {
- M_warn("GetCmapEntry", "Bad input");
- ci = 0;
- }
- for (i = 0; i < 3; i++)
- fc[i] = m->ct[i][ci];
- }
-
- /*
- * modify a colormap
- */
- void
- modify_cmap(CMPTR m, pc_t *r, pc_t *g, pc_t *b)
- {
- register pc_t *pc1 = m->ct[0], *pc2 = m->ct[1], *pc3 = m->ct[2];
- register pc_t *pcs;
-
- for (pcs = pc1 + m->colors; pc1 < pcs; pc1++, pc2++, pc3++)
- {
- *pc1 = r[*pc1];
- *pc2 = g[*pc2];
- *pc3 = b[*pc3];
- }
- m->packed = 0;
- }
-
- void
- pack_cmap(CMPTR m)
- {
- register pc_t *r = m->ct[0], *g = m->ct[1], *b = m->ct[2];
- register pc_t *rs;
- register rgba_t *rgba = m->p_h.rgba;
-
- if (m->packed > 0)
- return;
-
- for (rs = r + m->colors; r < rs; r++, g++, b++, rgba++)
- *rgba = Pack(*r, *g, *b);
- m->packed = 1;
- }
-
- void
- pack_cmap_g(CMPTR m)
- {
- register pc_t *r = m->ct[0], *g = m->ct[1], *b = m->ct[2];
- register pc_t *gr = m->ct[3], *rs;
-
- for (rs = r + m->colors; r < rs; r++, g++, b++, gr++)
- *gr = RGB2GRAY(*r, *g, *b);
- }
-
- /* find out the no. of uniq colors in a colormap */
- int
- cmap_ucolors(register CMPTR m, register pc_t *lut)
- {
- register int i, j, k;
-
- for (i = k = 0; i < m->colors; i++)
- lut[i] = i;
-
- pack_cmap(m);
-
- for (i = 0; i < m->colors; i++)
- {
- for (j = i + 1; j < m->colors; j++)
- {
- if (lut[j] == j && (m->p_h.rgba[i] == m->p_h.rgba[j]))
- {
- lut[j] = lut[i];
- k++;
- }
- }
- }
-
- return m->ucolors = m->colors - k;
- }
-
- /********************************************************************
- * Remove redundant entries from colormap and their index from image.
- * Further squeeze is possible if we actually check if all entries in
- * the map are actually used by examing the histograms
- *********************************************************************/
-
- void
- squeeze_image(IPTR im)
- {
- pc_t lutable[PCMAX];
- register CMPTR m = im->cmap;
- register pc_t *lut = lutable;
- register int i, j, k = 0;
-
- /*
- * cmap_ucolors will return a lookup table with entries lut[m] = n; with
- * m > n, meaning mth entry is not unique, and is the same as nth entry.
- * Also only worthwhiel to squeeze if we can save at least 1bit
- */
-
- if ((i = cmap_ucolors(m, lut)) <= m->colors / 2)
- {
- int tnlut[PCMAX];
- register ci_t *ci = im->raster, *cis;
- register CMPTR mm = get_mem_cmap();
- register int *nlut = tnlut;
-
- mm->ct[0][0] = m->ct[0][0];
- mm->ct[1][0] = m->ct[1][0];
- mm->ct[2][0] = m->ct[2][0];
-
- nlut[k++] = 0;
-
- for (i = 1; i < m->colors; i++)
- {
-
- j = lut[i];
-
- if (j == i) /* uniq */
- {
- mm->ct[0][k] = m->ct[0][i];
- mm->ct[1][k] = m->ct[1][i];
- mm->ct[2][k] = m->ct[2][i];
- nlut[i] = k++;
- }
- else
- {
- /* redundant, and j is smaller than i */
- nlut[i] = nlut[j];
- }
- }
-
- if (k != m->ucolors)
- {
- Bark("Squeeze", "Something is wrong %d %d", k, m->ucolors);
- free_mem_cmap(mm);
- return;
- }
-
- #ifdef MDEBUG
- for (i = 0; i < m->colors; i++)
- M_debug("Squeeze", "lut[%d]=%d nlut=%d\n", i, lut[i], nlut[i]);
- #endif
-
- /* change the index */
- for (cis = ci + im->w * im->h; ci < cis; ci++)
- *ci = nlut[*ci];
-
- im->colors = mm->colors = mm->ucolors = m->ucolors;
- im->cmap = mm;
- im->cmap->packed = 0;
- free_mem_cmap(m);
-
- im->io->display(im, 0, 0);
- }
-
- update_color_info(im);
- }
-
- /* this one should be completely rewritten */
- int
- cmap_closematch(CMPTR m, int r, int g, int b)
- {
- register int dr, dg, db;
- register unsigned long mindiff, cdiff;
- register int ci = 0, i;
-
- mindiff = ~0;
- for (i = 0; i < m->colors; i++)
- {
- dr = r - m->ct[0][i];
- dg = g - m->ct[1][i];
- db = b - m->ct[2][i];
- cdiff = (3 * (dr * dr) + 4 * (dg * dg) + 2 * (db * db));
-
- if (cdiff < mindiff)
- {
- mindiff = cdiff;
- ci = i;
- }
-
- /* special provision for exact match */
- if (cdiff == 0)
- goto exact;
- }
- exact:
- return ci;
- }
-
- /*****************************************************************
- * need to save the original colormap when program starts and
- * re-install the map when program quits. MAXMAP is 4096, but only
- * need to save and restore the map entries used (0--MAXCML)
- *****************************************************************/
-
- #define MAXMAP MAXCML
-
- static pc_t sysmap[3][MAXMAP];
- static int sysmap_ok;
-
- void
- get_sysmap(void)
- {
- long win;
-
- noport();
- win = winopen("");
- get_colmap(MAXMAP, sysmap[0], sysmap[1], sysmap[2]);
- winclose(win);
- sysmap_ok = 1;
- }
-
-
- void
- set_sysmap(int p)
- {
- long win;
-
- if (sysmap_ok)
- {
- noport();
- win = winopen("");
- set_colmap(MAXMAP, sysmap[0], sysmap[1], sysmap[2]);
- winclose(win);
- }
-
- if (p)
- print_before_exit();
- }
-
- /*********************************************************************
- * get a rectangular piece of image. (x,y) is the screen location
- * directly comparable to im->xi and im->yi, i.e., it is relative
- * to window
- ********************************************************************/
-
- void *
- get_subimage(IPTR im, int x, int y, int w, int h)
- {
- const char *fn = "Get_subimage";
-
- if (!image_ready(im, fn))
- return 0;
-
- if (x < im->xi || y < im->yi || h <= 0 || w <= 0 ||
- (x + w - 1) > im->xf || (y + h - 1) > im->yf)
- {
- Bark(fn, "Bad requested region");
- return 0;
- }
-
- /* now everything is ok. Do it */
- return get_submat(im->mraster, im->h, im->w,
- y - im->yi, x - im->xi, h, w, im->esize);
- }
-
- /*********************************************************************
- * Similar to get_subimage, but will never fail: if requested
- * region is outside the image, it will be filled by whatever
- * in the framebuffer. It will fail, however, if illogical
- * value such as w < 0 || h < 0 is passed
- **********************************************************************/
-
- void *
- no_fail_get_subimage(IPTR im, int x, int y, int w, int h)
- {
- char **ret;
-
- if (w <= 0 || h <= 0)
- {
- Bark("NoFailGetSubImage", "bad w and/or h");
- return 0;
- }
-
- if (x < im->xi || y < im->yi ||
- (x + w - 1) > im->xf || (y + h - 1) > im->yf)
- {
- int ux, uy, uw, uh;
- rgba_t fillc = (IS_CPACK(imgptr) ? background_color : BKINDEX);
-
- ret = get_mat(h, w, im->esize);
-
- /* initialize it to background color */
- init_mat(ret, h, w, im->esize, fillc);
-
- /* need to replace the union with the piece from raster */
- ux = Max(im->xi, x);
- uy = Max(im->yi, y);
-
- uw = Min(im->xf, (x + w - 1)) - ux + 1;
- uh = Min(im->yf, (y + h - 1)) - uy + 1;
-
- if (uw > 0 && uh > 0) /* union exists */
- {
- void *p = get_subimage(im, ux, uy, uw, uh);
- int oop = get_mat_op();
-
- /* Insert sm into framebuffer matrix. Always in NOOP mode */
- set_mat_op(O_NONE);
- put_submat(ret, h, w, p,
- uy - y, ux - x, uh, uw, im->esize);
- set_mat_op(oop);
- free_mat(p);
- }
- }
- else
- {
- /* within image */
- ret = get_subimage(im, x, y, w, h);
- }
- return ret;
- }
-
- int
- put_subimage(IPTR im, void *m, const Rect_t * r, int warn)
- {
- static const char *fn = "PutSubImage";
- const Rect_t *o;
- void *sm;
-
- if (!image_ready(im, fn))
- return -1;
-
- if (!(o = union_rect(r, img_rect(im))))
- {
- if (warn)
- Bark(fn, "Bad requested region");
- return -1;
- }
-
- if (equal_rect(r, o))
- {
- return put_submat(im->mraster, im->h, im->w,
- m, r->y - im->yi, r->x - im->xi, r->h, r->w, im->esize);
- }
-
- /* clip */
- sm = get_submat(m, r->h, r->w,
- o->y - r->y, o->x - r->x, o->h, o->w, im->esize);
- put_submat(im->mraster, im->h, im->w, sm,
- o->y - im->yi, o->x - im->xi, o->h, o->w, im->esize);
- free_mat(sm);
- return 0;
- }
-
-
- /***********************************************************************
- * given several keys, say ppm, pgm and pbm, check if any of the keys has
- * the same type as the current image, if there is, return the index into
- * the img_io, else if no match can be found, return the first match.
- * Therefore, the caller should always place the keys in decreasing order
- * in generality, i.e, ppm, pgm and pbm, NEVER pbm, pgm and ppm
- **********************************************************************/
- int
- best_format(IPTR im, char *const *keys)
- {
- char *const *q = keys;
- int i, first = -1;
- int bestsofar = totalfmt + 1; /* negative match, positive best */
- int best;
-
- if (!*q || !im->ok)
- {
-
- #ifdef MDEBUG
- M_debug("BestFmt", "Bad input");
- #endif
- return -1;
- }
-
-
- do
- {
- /* go thru all images and check for key match */
- for (i = 0; i < totalfmt && strcasecmp(img_io[i].key, *q); i++)
- ;
-
- /* we have found a match at i, check if type OK */
- if (i < totalfmt)
- { /* match */
- bestsofar = (im->type == img_io[i].type ||
- img_io[i].type == T_FLEX) ? i : -i;
-
- /* remember the first match */
- if (first < 0)
- first = i; /* first match */
- }
-
- #ifdef MDEBUG
- else
- {
- M_debug("BestFmt", "%s not found", *q);
- }
- #endif
-
- }
- while (*++q && (bestsofar < 0 || bestsofar > totalfmt));
-
- /* the best one */
- best = (bestsofar > totalfmt) ? -1 : (bestsofar >= 0 ? bestsofar : first);
-
- M_info("BestFmt", "1stReq %s, Best %s",
- keys[0], (best >= 0) ? img_io[best].key : "none");
-
- return best;
- }
-
- /***********************************************************************
- * image type conversions
- * quantization is in a separate file due to its size
- ***********************************************************************/
-
- #include "lookup.h" /* lookup tables */
-
- /**** given RGB, get the packed pixel for display *****/
- static void
- rgb_to_cpack(register rgba_t *p, register pc_t *r,
- register pc_t *g, register pc_t *b, long sz)
- {
- register pc_t *rs;
-
- if (r == g)
- { /* grayscale */
- for (rs = r + sz; r < rs; r++)
- *p++ = Pack(*r, *r, *r);
- }
- else
- {
- for (rs = r + sz; r < rs; r++, g++, b++)
- *p++ = Pack(*r, *g, *b);
- }
- }
-
- int
- img_rgb_to_cpack(IPTR im)
- {
- register pc_t *r, *g, *b;
- register long total = im->h * im->w;
-
- if (!im->pc[0])
- {
- Bark("Packing", "Bad RGB matrix");
- return -1;
- }
-
- r = im->pc[0][0];
- g = im->pc[1][0];
- b = im->pc[2][0];
-
- im->type = (IS_GRAY(im) || r == g) ? T_GRAY : T_RGBA;
-
- if (img_get_rastermem(im) >= 0)
- {
- if (im->type == T_RGBA)
- {
- rgb_to_cpack(im->raster, r, g, b, total);
- }
- else
- {
- rgb_to_cpack(im->raster, r, r, r, total);
- }
- im->ok = 1;
- }
-
- return im->ok ? 0 : -1;
- }
-
- /******* given a cpack, take it apart to get RGB *******/
- static int
- cpack_to_rgb(IPTR im)
- {
- register pc_t *r, *g, *b;
- register rgba_t *rgba, *rs;
- register int total = im->w * im->h;
- int status;
-
- if ((status = img_get_rgbmem(im)) >= 0)
- {
- rgba = im->raster;
- r = im->pc[0][0];
- g = im->pc[1][0];
- b = im->pc[2][0];
- for (rs = rgba + total; rgba < rs; r++, g++, b++, rgba++)
- {
- CPACK2RGB(*rgba, *r, *g, *b);
- }
- }
- return status;
- }
-
- /******** given a cmap img, get RGB triplets *********/
- static int
- cmap_to_rgb(IPTR im)
- {
- register pc_t *r, *g, *b;
- register pc_t *mr, *mg, *mb;
- register ci_t *ras = im->raster, *rs;
- register int total = im->w * im->h;
- int status;
-
- if ((status = img_get_rgbmem(im)) >= 0)
- {
- mr = im->cmap->ct[0];
- mg = im->cmap->ct[1];
- mb = im->cmap->ct[2];
- r = im->pc[0][0];
- g = im->pc[1][0];
- b = im->pc[2][0];
- for (rs = ras + total; ras < rs; ras++)
- {
- *r++ = mr[*ras];
- *g++ = mg[*ras];
- *b++ = mb[*ras];
- }
- }
- else
- {
- Bark("cmap2cpack", mfailed);
- }
- return status;
- }
-
- /***** get RGB triplets from an image *****/
-
- int
- img_get_rgb(IPTR im)
- {
- return (!im || !im->raster) ? -1 :
- (IS_CI(im) ? cmap_to_rgb : cpack_to_rgb) (im);
- }
-
- /***** fill some fields of image structure ******/
-
- int
- fill_image_struct(IPTR im, void *m, int h, int w, IMG_TYPE t)
- {
- if (!m || w < 1 || h < 1)
- {
- M_err("ImageFill", "Bad input");
- return -1;
- }
-
- /*
- * need to make sure m and im->mraster are different before messing with
- * im->mraster
- */
- if (im->mraster != m)
- img_free_rastermem(im);
-
- im->w = w;
- im->h = h;
- im->mraster = m;
- im->raster = ((char **) m)[0];
-
- /* get the pixel size */
- if (t == T_CMAP)
- im->esize = sizeof(ci_t);
- else if (t == T_GRAY)
- im->esize = sizeof(gray_t);
- else if (t == T_RGBA)
- im->esize = sizeof(rgba_t);
- else if (t == T_GMAP)
- im->esize = sizeof(ci_t);
- else if (t == T_BW)
- im->esize = sizeof(bw_t);
- else
- return -1;
-
- im->size = im->esize * w * h;
- im->ok = 1;
- im->type = t;
- update_image_info(im);
- return 0;
- }
-
- /** Create an image of solid colors *********/
- IPTR
- create_image(const char *name, int type, int w, int h, rgba_t col)
- {
- IPTR im;
-
- if (w <= 0 || h <= 0)
- {
- M_err("ImageCreate", "Bad arg w=%d h=%d\n", w, h);
- return 0;
- }
-
- (im = get_mem_imgptr())->cmap = get_mem_cmap();
- im->type = type;
- im->w = w;
- im->h = h;
-
- /* fill the raster */
- img_get_rastermem(im);
- init_mat(im->mraster, im->h, im->w, im->esize, col);
-
- im->ok = 1;
-
- strcpy(im->ifile, (name && *name) ? name : "untitled");
- im->info = "Internal";
- im->key = "?";
-
- im->io = &img_io[0];
- im->io->display = Generic_display;
- return im;
- }
-
- /********************************************************************
- * Convert from colormapped image to RGBA
- *
- * the mask is important since the mapped image might be a result of
- * screen read and if writemask is not set properly (not set at all
- * at this moment), the index will be full 12bits. Only the bits
- * with mask are meaningful
- **********************************************************************/
-
- static int
- cmap_to_cpack(IPTR im)
- {
- /*
- * can't simply use no. of colors as masks because it might not be 2^n,
- * e.g., sunraster file
- */
- int p = power_of_2(im->cmap->colors);
- register ci_t mask = (p > MAXCML ? MAXCML : p) - 1;
- register ci_t *ci = im->raster, *cis;
- register rgba_t *ras, *mp, **m;
-
- if (!(m = get_mat(im->h, im->w, sizeof(rgba_t))))
- {
- Bark("CmapToCpack", mfailed);
- return -1;
- }
- pack_cmap(im->cmap);
- mp = im->cmap->p_h.rgba;
- ras = m[0];
-
- for (cis = ci + im->h * im->w; ci < cis; ci++, ras++)
- *ras = *(mp + ((*ci) & mask));
- return fill_image_struct(im, m, im->h, im->w,
- ((im->type == T_GMAP || im->type == T_BW) ? T_GRAY : T_RGBA));
- }
-
- /***** convert from RGBA to grayscale ****/
- int
- rgb2gray(int r, int g, int b)
- {
- return RGB2GRAY(r, g, b);
- }
-
- int
- cpack2gray(rgba_t c)
- {
- return CPACK2GRAY(c);
- }
-
- static int
- cpack_to_gray(IPTR im)
- {
- register rgba_t *p = im->raster, *ps;
- int total = im->w * im->h;
-
- if (!IS_RGBGRAY(im))
- {
- for (ps = p + total; p < ps; p++)
- {
- *p = CPACK2GRAY(*p);
- *p = RGB2CPACK(*p, *p, *p);
- }
- im->type = T_GRAY;
- }
- return 0;
- }
-
- /***** map based grayscale will turn into T_GMAP ****/
-
- static int
- cmap_to_mgray(IPTR im)
- {
- register rgba_t p;
- register pc_t *r = im->cmap->ct[0], *rs;
- register pc_t *g = im->cmap->ct[1];
- register pc_t *b = im->cmap->ct[2];
-
- if (!IS_MGRAY(im))
- {
- for (rs = r + im->cmap->colors; r < rs; r++, g++, b++)
- {
- p = RGB2GRAY(*r, *g, *b);
- *r = *g = *b = (pc_t) p;
- }
- im->cmap->packed = 0; /* very important */
- im->type = T_GMAP;
- }
- return 0;
- }
-
- static int
- cmap_to_gray(IPTR im)
- {
- return (cmap_to_mgray(im) < 0 || cmap_to_cpack(im) < 0) ? -1 : 0;
- }
-
- #if 0 /*** {***/
- int
- img_to_gray(IPTR im)
- {
- int status;
-
- if (!im || !im->raster)
- return -1;
-
- if (IS_GRAY(im))
- return 0;
- status = (IS_CPACK(im)) ?
- cpack_to_gray(im) : cmap_to_mgray(im);
- text_to_gray();
- sgf_to_gray();
- update_image_info(im);
- return status;
- }
- #endif /****}**/
-
- /* ARGSUSED */
- static int
- noop(IPTR im)
- {
- return 0;
- }
-
- static int
- cpack_to_gmap(IPTR im)
- {
- return (cpack_to_gray(im) < 0 || rgb_to_cmap(im) < 0) ? -1 : 0;
- }
-
-
- static int
- cpack_to_bw(IPTR im)
- {
- return img_half_toning(im);
- }
-
- /********* convert to cpack and then to B&W **************/
-
- static int
- cmap_to_bw(IPTR im)
- {
- return (cmap_to_cpack(im) >= 0) ? cpack_to_bw(im) : -1;
- }
-
- /******************************************************
- * Global interface to convert image types
- *
- ******************************************************/
-
- /*
- * Set up the type conversion matrix, with proper provisions for T_FLEX and
- * other types, then everything is reduced to a table lookup
- */
-
- typedef int (*fcnvt) (IPTR);
- typedef int (*fprecnvt) (void);
-
- typedef struct
- {
- IMG_TYPE from, to; /* image types */
- fprecnvt precnvt; /* if preparation is needed */
- fcnvt cnvt; /* do it */
- } convt_s;
-
- static convt_s conv[] =
- {
-
- /* start with colormapped images */
- {T_CMAP, T_RGBA, 0, cmap_to_cpack},
- {T_CMAP, T_GMAP, 0, cmap_to_mgray},
- {T_CMAP, T_GRAY, 0, cmap_to_gray},
- {T_CMAP, T_BW, pre_bw, cmap_to_bw},
- {T_CMAP, T_RGB, 0, cmap_to_rgb},
-
- /* start with graymap images */
- {T_GMAP, T_GRAY, 0, cmap_to_cpack},
- {T_GMAP, T_RGBA, 0, cmap_to_cpack},
- {T_GMAP, T_BW, pre_bw, cmap_to_bw},
- {T_GMAP, T_CMAP, 0, noop},
- {T_GMAP, T_RGB, 0, cmap_to_rgb},
-
- /* start with cpack */
- {T_RGBA, T_GRAY, 0, cpack_to_gray},
- {T_RGBA, T_CMAP, pre_quant, rgb_to_cmap},
- {T_RGBA, T_GMAP, pre_quant, cpack_to_gmap},
- {T_RGBA, T_BW, pre_bw, cpack_to_bw},
- {T_RGBA, T_RGB, 0, cpack_to_rgb},
-
- /* start with RGBA gray */
- {T_GRAY, T_RGBA, 0, noop},
- {T_GRAY, T_GMAP, pre_quant, rgb_to_cmap},
- {T_GRAY, T_CMAP, pre_quant, rgb_to_cmap},
- {T_GRAY, T_BW, pre_bw, cpack_to_bw},
-
- /* start with B&W */
- {T_BW, T_GMAP, 0, noop},
- {T_BW, T_CMAP, 0, noop},
- {T_BW, T_GRAY, 0, cmap_to_cpack},
- {T_BW, T_RGBA, 0, cmap_to_cpack},
- /* sentinels */
- {T_INVALID, T_INVALID, 0}
- };
-
- int
- img_convert_type(IPTR im, IMG_TYPE newtype)
- {
- register int found;
- register convt_s *p;
- int cancel = 0;
-
-
- if (!im || !im->raster)
- {
- Bark("TypeConvert", "Bogus input");
- return -1;
- }
-
- /* check for special cases: A Flex type means any type is ok */
- if (newtype == T_FLEX || im->type == newtype)
- return 0;
-
- /* we'll be generating new colormaps */
- if (newtype == T_CMAP || newtype == T_GMAP)
- im->cmap->packed = 0;
-
- /* get the appropriate function */
- for (p = &conv[0], found = 0; !found && p->from != T_INVALID; p++)
- found = p->from == im->type && p->to == newtype;
-
- if (!found)
- {
- to_be_written("ConvertType");
- return 1;
- }
-
- /* last chance to back off, indicated by cancel */
- if ((--p)->precnvt)
- cancel = p->precnvt();
-
- return cancel ? -1 : p->cnvt(im);
- }
-
- /**************************************************************
- * switch black and white: special service to all bw images
- **************************************************************/
-
- void
- bw_special(IPTR im)
- {
- register pc_t b;
- register CMPTR m = im->cmap;
-
- if (IS_BW(im))
- {
- b = m->ct[0][0];
- m->ct[0][0] = m->ct[1][0] = m->ct[2][0] = m->ct[0][1];
- m->ct[0][1] = m->ct[1][1] = m->ct[2][1] = b;
- set_cmap(m);
- }
- }
-
- /*****************************************************************
- * normalize a primary color vector of length n to within
- * (imin, imax)
- *******************************************************************/
- void
- normal_pc_vec(pc_t *vec, int n, int imin, int imax)
- {
- register pc_t *v = vec, *vs;
- register int vmin, vmax;
- register float a, b;
-
- vmin = vmax = *v;
-
- for (vs = v + n; v < vs; v++)
- {
- if (vmin > *v)
- vmin = *v;
- if (vmax < *v)
- vmax = *v;
- }
-
- if (imin == vmin && imax == vmax) /* already normalized */
- return;
- if (vmax == vmin) /* bad stuff */
- return;
-
- a = ((float) imax - imin) / (float) (vmax - vmin);
- b = imin - a * vmin;
-
- for (v = vec; v < vs; v++)
- *v = ((float) *v * a + b + 0.5);
- return;
- }
-
- /* interpolate a primary color vector of n to np */
- void
- interpolate_pc_vec(register pc_t *vin, int n,
- register pc_t *vout, int np)
- {
- register float sx, dx, f;
- int kx, kx1;
- int i;
-
- sx = (float) (n - 1.0) / (np - 1.0);
- for (i = 0; i < np; i++)
- {
- dx = sx * i;
- kx = dx;
- dx = dx - kx;
- kx1 = kx + (kx < n - 1);
- f = vin[kx];
- f += dx * (vin[kx1] - f);
- vout[i] = (f + 0.5);
- }
- return;
- }
-
- /*
- * Default colormaps for bit in displaying edge maps and other
- * stuff.
- */
- typedef struct
- {
- int n; /* no. of entries */
- pc_t red[PCMAX];
- pc_t grn[PCMAX];
- pc_t blue[PCMAX];
- short pcmin, pcmax; /* channel range */
- short rave, gave, bave; /* average in map */
- }
- DefMap;
-
- #define MAXDEFMAP 18
- static DefMap *defmaps[MAXDEFMAP];
- static int nmap;
-
- static int
- load_defmap_fp(FILE * fp)
- {
- int done, k, n;
- register pc_t *r, *g, *b, *rs;
- register long rave, gave, bave;
- DefMap *m;
-
- k = nmap;
- do
- {
- done = (n = readpint(fp)) < 0;
- if (!done)
- {
- m = defmaps[k] = malloc(sizeof(*defmaps[0]));
- m->n = n;
- m->pcmin = readpint(fp);
- m->pcmax = readpint(fp);
- r = m->red;
- g = m->grn;
- b = m->blue;
- rave = gave = bave = 0;
- for (rs = r + n; r < rs; r++, g++, b++)
- {
- rave += (*r = readpint(fp));
- gave += (*g = readpint(fp));
- bave += (*b = readpint(fp));
- }
- m->rave = rave / n;
- m->gave = gave / n;
- m->bave = bave / n;
- ++k;
- }
- }
- while (!done);
- return k - nmap;
- }
-
- static int
- load_defmap(void)
- {
- static const char *mapfile = "defmap.map";
- FILE *fp;
- int k = 0;
-
- if (nmap > 0)
- return nmap;
-
- /* try system directory first */
- if ((fp = get_HELPfile_fp(mapfile, "r")))
- {
- k = nmap = load_defmap_fp(fp);
-
- #ifdef MDEBUG
- M_debug("DefMap", "Got %d maps from SysDir", nmap);
- #endif
- fclose(fp);
- }
-
- /* user directory */
- if ((fp = get_BITfile_fp(mapfile, "r")))
- {
- k = k + load_defmap_fp(fp);
-
- #ifdef MDEBUG
- M_debug("DefMap", "Got %d maps from UserDir", k - nmap);
- #endif
-
- nmap = k;
- fclose(fp);
- }
- M_info("LoadDefMap", "Total %d maps found", nmap);
- return nmap;
- }
-
- /*
- * get default map. a zero indicates grayscale map. Colormap so generated
- * will always have the correct range regardless how many entries are
- * requested
- */
- void
- get_bit_defmap(int n, register pc_t *r, register pc_t *g,
- register pc_t *b, int req)
- {
- int i;
- register pc_t *rr, *gg, *bb;
- DefMap *m;
-
- if (!nmap)
- nmap = load_defmap();
-
- #ifdef MDEBUG
- M_debug("DefMap", "Getting %d from total of %d", n, nmap);
- #endif
-
- if (n < 0 || n > nmap)
- n = 0;
-
- if (n == 0)
- { /* default gray */
- float a = (float) PCMAXV / req;
- for (i = 0; i < req; i++, r++, g++, b++)
- *r = *g = *b = (a * i + 0.5);
- return;
- }
-
- --n;
- m = defmaps[n];
- rr = m->red;
- gg = m->grn;
- bb = m->blue;
-
- /* check if map is normalized */
- if ((m->pcmax - PCMAXV) || (m->pcmin != 0))
- {
- normal_pc_vec(rr, m->n, 0, PCMAXV);
- normal_pc_vec(gg, m->n, 0, PCMAXV);
- normal_pc_vec(bb, m->n, 0, PCMAXV);
- m->pcmin = 0;
- m->pcmax = PCMAXV;
- }
- /* check if length match */
- if (req != m->n)
- {
- interpolate_pc_vec(rr, m->n, r, req);
- interpolate_pc_vec(gg, m->n, g, req);
- interpolate_pc_vec(bb, m->n, b, req);
-
- if (req > m->n && req < PCMAX)
- {
- memcpy(rr, r, sizeof(pc_t) * req);
- memcpy(gg, g, sizeof(pc_t) * req);
- memcpy(bb, b, sizeof(pc_t) * req);
- m->n = req;
- }
- }
- else
- {
- memcpy(r, rr, sizeof(pc_t) * req);
- memcpy(g, gg, sizeof(pc_t) * req);
- memcpy(b, bb, sizeof(pc_t) * req);
- }
- return;
- }
-
- int
- get_number_of_defmaps(void)
- {
- return nmap ? nmap : (nmap = load_defmap());
- }
-
- /* set format specific info */
- void
- set_iformat_info(IPTR im, const char *s)
- {
- if (s && im)
- Strncpy(im->misc, s, MAXINFO - 1);
- }
-
- /******************************************************************
- * read a piece of framebuffer and save it to the image in core mem.
- * Also clip to the edge of the image.
- *
- * Due to the way geomtric figure is handled in bit, negative w and/or h
- * is possible.
- ******************************************************************/
- void
- fb_to_ras(IPTR im, const Rect_t * r)
- {
- char **pp;
- const Rect_t *o, *u;
- static const char *fn = "FB2RAS";
- long odraw = getdrawmode();
- Rect_t tmp;
-
-
- drawmode(NORMALDRAW);
-
- /*
- * read it only if overlap. Also we should not allow the src rectangle to
- * be outside of the window
- */
- copy_rect(&tmp, r);
- u = union_rect(canonicalize_rect(&tmp), img_rect(im));
- if (u && (o = union_rect(u, make_rect(0, 0, win_w - 1, win_h - 1))))
- {
- Rect_t p;
- /*
- * always a good idea to copy the union as other routines might
- * overwrite the static buffer
- */
- copy_rect(&p, o);
- M_info(fn, "x=%d y=%d w=%d h=%d", p.x, p.y, p.w, p.h);
- pp = get_mat(p.h, p.w, im->esize);
- Rectread(p.x, p.y, p.x + p.w - 1, p.y + p.h - 1, pp[0]);
- put_subimage(im, pp, &p, 0);
- free_mat(pp);
- }
- else
- {
- M_info(fn, "no overlap");
- }
-
- drawmode(odraw);
- }
-
-
- /*
- * To minimize interference with window manager, we manipulate the
- * image so that some of the wm colors are preserved. Different wm
- * may use different schemes for lut, we will have to give the color
- * in RGB representation and search the default colormap for the index
- * For images where index has meaning, e.g., intensity, etc., set
- * preserve_wm_colors to zero to supress color swapping.
- */
-
- typedef struct
- {
- rgba_t rgba; /* colors to preserve */
- ci_t ci; /* its index in default sysmap */
- }
-
- Wmcolor;
-
- /*
- * because collision is not taken care of, the colors that must be
- * preserved should be the last one in table
- */
- static Wmcolor wmcolor[] =
- {
- {0x00ffffff, 0}, /* white */
- {0, 0} /* black */
- };
-
- #define SwapMapEntry(m, i, j) \
- do { int r_, g_, b_; \
- r_ = m->ct[0][i]; \
- g_ = m->ct[1][i]; \
- b_ = m->ct[2][i]; \
- m->ct[0][i] = m->ct[0][j]; \
- m->ct[1][i] = m->ct[1][j]; \
- m->ct[2][i] = m->ct[2][j]; \
- m->ct[0][j] = r_; \
- m->ct[1][j] = g_; \
- m->ct[2][j] = b_; \
- } while (ZERO)
-
- #define DOGROUP /* if more than 1 reserved color, define this */
-
- void
- img_preserve_wm_colors(IPTR im)
- {
- static int first = 1;
- int tran;
- int i, pr, pg, pb, k;
- int npreserve = sizeof(wmcolor) / sizeof(wmcolor[0]);
- CMPTR m = im->cmap;
-
- #ifdef DOGROUP
- ci_t allt[MAXCML];
-
- /* initialize the transformation table */
- for (i = 0; i < m->colors; i++)
- allt[i] = i;
- #endif
-
- /* search the default system map for black and white */
- if (first)
- {
- int r, g, b;
- unsigned long mdiff, cdiff;
- for (k = 0; k < npreserve; k++)
- {
- Unpack(wmcolor[k].rgba, pr, pg, pb);
- mdiff = ~0;
- for (i = 0; i < 15; i++)
- {
- r = (pr - sysmap[0][i]);
- g = (pg - sysmap[1][i]);
- b = (pb - sysmap[2][i]);
- cdiff = 3 * r * r + 4 * g * g + 2 * b * b;
- if (cdiff < mdiff)
- {
- wmcolor[k].ci = i;
- mdiff = cdiff;
- }
- }
- }
- first = 0;
- }
-
- /*
- * re-arrange the colormap so that requested colors to be preserved. have
- * the same index in current map and system map could be slow if
- * npreserve is large
- */
-
- for (k = 0; k < npreserve; k++)
- {
- /*
- * since we only will use m->colors, there is no point to preserve
- * colors indeces that are larger than m->colors
- */
-
- if (wmcolor[k].ci >= m->colors)
- continue;
-
- Unpack(wmcolor[k].rgba, pr, pg, pb);
- tran = cmap_closematch(m, pr, pg, pb);
-
- #ifdef MDEBUG
-
- M_debug("PreserveWMcol", "Need r=%d g=%d b=%d at %d",
- pr, pg, pb, wmcolor[k].ci);
-
- M_debug("PreserveWMcol", "Found r=%d g=%d b=%d at %d with total %d",
- m->ct[0][tran], m->ct[1][tran], m->ct[2][tran], tran,
- m->colors);
- #endif
-
- #ifndef DOGROUP
- if (tran != wmcolor[k].ci)
- {
- modify_ci_pixel(im->raster, im->w * im->h,
- wmcolor[k].ci, tran, 1);
- SwapMapEntry(m, wmcolor[k].ci, tran);
- }
- #else
- if (tran != wmcolor[k].ci)
- {
- allt[allt[wmcolor[k].ci]] = tran;
- allt[tran] = wmcolor[k].ci;
- SwapMapEntry(m, wmcolor[k].ci, tran);
- }
- #endif
- }
-
- /* reset pack flag */
- im->cmap->packed = 0;
- #ifdef DOGROUP
- modify_all_ci(im->raster, im->w * im->h, allt);
- #endif
- }
-
- #if 0 /* UNTESTED {** */
- /*
- * Instead of preserve a few selected color, we try to preserval
- * all colors, upto 256
- */
- void
- preserve_all_colors(IPTR im)
- {
- ci_t tran[MAXCML];
- int used[MAXCML];
- CMPTR m = im->cmap;
- int i, j, k;
-
- progress_report("", 100);
- for (i = 0; i < m->colors; i++)
- {
- tran[i] = i;
- used[i] = 0;
- }
-
- for (i = 0; i < m->colors; i++)
- {
- j = cmap_closematch(m, sysmap[0][i],
- sysmap[1][i], sysmap[2][i]);
- if (!used[j] && !used[i] && i != j)
- {
- tran[tran[i]] = j;
- tran[j] = i;
- SwapMapEntry(m, i, j);
- }
- used[j] = 1;
- }
- m->packed = 0;
- modify_all_ci(im->raster, im->w * im->h, tran);
- remove_progress_report();
- }
- #endif /** } **/
-
-
- /********************************************************************
- * simulate double buffering
- *
- * Normal Frame buffer and over/pup buffer
- *
- *******************************************************************/
-
- #ifndef NO_NP_DBL
-
- /***********************************************************
- * Move an object given by obj having (w,h) as its dimension
- * from (ox, oy) to (x,y).
- ***********************************************************/
-
- void
- sim_dbl_swap(IPTR im, int w, int h, void *obj,
- int x, int y, int ox, int oy, int mop)
- {
-
- int x1, x2, y1, y2;
- int sw, sh;
- static void **scrn;
-
- set_mat_op(mop);
-
- /* if almost disjoint, not point simulating double buffering */
- if (Abs(ox - x) > (0.8 * w) && Abs(oy - y) > (0.8 * h))
- {
- void **pp;
-
- /* erase the old one */
- img_rect_redraw(im, ox, oy, w, h);
- /* draw the new one */
- pp = no_fail_get_subimage(im, x, y, w, h);
- put_submat(pp, h, w, obj, 0, 0, h, w, im->esize);
- PI_rectwrite(x, y, x + w - 1, y + h - 1, pp[0]);
- free_mat(pp);
- }
- else
- {
- x1 = Min(ox, x) - 1;
- x2 = Max(ox, x) + w + 1;
-
- y1 = Min(oy, y) - 1;
- y2 = Max(oy, y) + h + 1;
- sw = x2 - x1 + 1;
- sh = y2 - y1 + 1;
-
- free_mat(scrn);
- scrn = no_fail_get_subimage(im, x1, y1, sw, sh);
- put_submat(scrn, sh, sw, obj, y - y1, x - x1, h, w, im->esize);
- PI_rectwrite(x1, y1, x1 + sw - 1, y1 + sh - 1, scrn[0]);
- }
- set_mat_op(O_NONE);
- }
-
- void
- mv_ras_obj(void **obj, int w, int h, int ox, int oy, int x, int y)
- {
- /* sanity checks */
-
- if (!obj || !obj[0] || w <= 0 || h <= 0)
- {
- Bark("MovRasObj", "Bad input");
- return;
- }
-
- if (double_buf)
- {
- PI_rectwrite(x, y, x + w - 1, y + h - 1, obj[0]);
- swapbuffers();
- img_rect_redraw(imgptr, ox, oy, w, h);
- }
- else
- {
- sim_dbl_swap(imgptr, w, h, obj, x, y, ox, oy, O_NONE);
- }
- }
-
- #endif /* !NO_NP_DBL */
-
- /********************************************************************
- * Get same color but with different intensity.
- * Also subject (cmin, cmax) check
- ********************************************************************/
- void
- scale_color(int col[], float factor, int scaled[], int cmin, int cmax)
- {
-
- if (IS_CPACK(imgptr))
- {
- scaled[0] = col[0] * factor;
- scaled[1] = col[1] * factor;
- scaled[2] = col[2] * factor;
- }
- else if (IS_CI(imgptr))
- {
- CMPTR m = imgptr->cmap;
- int ci = col[4];
-
- Range(ci, 0, m->colors - 1);
- scaled[0] = factor * m->ct[0][ci];
- scaled[1] = factor * m->ct[1][ci];
- scaled[2] = factor * m->ct[2][ci];
- }
-
- Range(scaled[0], cmin, cmax);
- Range(scaled[1], cmin, cmax);
- Range(scaled[2], cmin, cmax);
-
- /* make sure we return valid PC */
- Range(scaled[0], 0, PCMAXV);
- Range(scaled[1], 0, PCMAXV);
- Range(scaled[2], 0, PCMAXV);
-
- if (IS_CI(imgptr))
- {
- scaled[3] = cmap_closematch(imgptr->cmap,
- scaled[0],
- scaled[1],
- scaled[2]);
- }
- }
-
- /*******************************************************************
- * Return a one-liner info about image im
- ******************************************************************/
- const char *
- image_vital_info(IPTR im)
- {
- static char buf[1024];
- sprintf(buf, "(%dX%d %s)", im->w, im->h, im->key);
- return buf;
- }
-
- #if 0 /** } **/
- /*********************************************************************
- * Pack a char stream (with padding) to pixel in cpack format
- *********************************************************************/
- void
- char_stream4_cpack(register rgba_t *rgba,
- register unsigned char *pc, long total, int rgb)
- {
- register rgba_t *rs = rgba + total;
-
- if (rgb)
- {
- for (; rgba < rs;)
- {
- pc++; /* skip alpha */
- *rgba++ = Pack(*pc, *(pc + 1), *(pc + 2));
- pc += 3;
- }
- }
- else
- {
- /* in RGB order */
- for (; rgba < rs;)
- {
- pc++; /* skip alpha */
- *rgba++ = Pack(*(pc + 2), *(pc + 1), *pc);
- pc += 3;
- }
- }
- }
-
- /********************************************************************
- * Pack a char stream (no padding) bytes into a pixel
- ********************************************************************/
- void
- char_stream3_cpack(rgba_t *rgba, unsigned char *pc, long total, int rgb)
- {
- register rgba_t *rs = rgba + total;
-
- if (rgb)
- {
- for (; rgba < rs;)
- {
- *rgba++ = Pack(*pc, *(pc + 1), *(pc + 2));
- pc += 3;
- }
- }
- else
- {
- /* in GBR order */
- for (; rgba < rs;)
- {
- *rgba++ = Pack(*(pc + 2), *(pc + 1), *pc);
- pc += 3;
- }
- }
- }
-
- #endif /** } **/
-
- /**********************************************************************
- * Anti-aliasing
- * It doesn't look right if linewidth != 1 or the linestyle is
- * not solid
- *********************************************************************/
- void
- smooth_line_on(IPTR im, int *col, int lw)
- {
- Color4(col);
-
- if (smooth_lines && getlstyle() == 0 &&
- sml_capable() && lw == 1 && IS_CPACK(im))
- {
- pntsmooth(SMP_ON | SMP_SMOOTHER);
- linesmooth(SML_ON | SML_SMOOTHER | SML_END_CORRECT);
- blendfunction(BF_SA, BF_MSA);
- subpixel(1);
- cpack(Pack(col[0], col[1], col[2]) | 0xff000000);
- }
- }
-
- /*********** Turn anti-aliasing off ******************/
- void
- smooth_line_off(IPTR im, int *col)
- {
- pntsmooth(SMP_OFF);
- linesmooth(SML_OFF);
- blendfunction(BF_ONE, BF_ZERO);
- subpixel(0);
- if (IS_CPACK(im))
- cpack(Pack(col[0], col[1], col[2]));
- }
-
- /************************************************************
- * Convert X11 bitmap to GL 32x32 patterns
- ************************************************************/
- #define getbits(a, k, i) ((a[(k)] >> (i))&1)
- #define GL_pat unsigned short
-
- GL_pat *
- XBM_to_GL_pat(int w, int h, char *bits)
- {
- GL_pat *pat, *cpat;
- int i, j, k, on, total;
-
- if (w != 32 || h != 32 || !bits)
- {
- M_err("XBM2GLPAT", "Bad input w=%d h=%d", w, h);
- return 0;
- }
-
- total = (w / 16) * h;
-
- /* do the conversion */
- pat = calloc((total + 1), sizeof(*pat));
- cpat = pat + total - 1;
-
- for (k = j = 0; j < h; j++)
- {
- for (i = 0; i < w; i++)
- {
- on = (bits[k + i / 8] & (1 << (i % 8))) != 0;
- *(cpat - (i / 16)) |= on << (15 - (i % 16));
- }
- k += (w + 7) / 8;
- cpat -= (w + 15) / 16;
- }
- return pat;
- }
-
- const Rect_t *
- img_rect(IPTR im)
- {
- static Rect_t dummy[5];
- static int np;
- Rect_t *r;
-
- r = dummy + np++;
-
- r->x = im->xi;
- r->y = im->yi;
- r->w = im->w;
- r->h = im->h;
-
- np %= 5;
- return r;
- }
-